//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
/*++

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name: 

        usb20fn.h

Abstract:

        PXA USB Function Driver Header.

--*/
#ifndef __PXA_USB20FN_H_
#define __PXA_USB20FN_H_

#include <xllp_defs.h>
#include <xllp_dmac.h>
#include "xllp_gpio.h"
#include "xllp_mfp.h"
#include "xllp_pm.h"
#include <xllp_u2d.h>
#include "xllp_clkmgr.h"

#include <csync.h>
#include <cmthread.h>
#include <CRegEdit.h>
#include <CRefCon.h>
#include <usbfn.h>


#ifndef SHIP_BUILD
#define STR_MODULE _T("monahans_usb20fn!")
#define SETFNAME() LPCTSTR pszFname = STR_MODULE _T(__FUNCTION__) _T(":")
#else
#define SETFNAME()
#endif

class USB20Device ;
class USB20Endpoint ;

#define USB20_DESCRIPTORS_MAX 32
#define USB20_DMA_BUFFER_SIZE 0x4000


// Endpoint Interrupt After shift.
#define EPINT_PACKET_COMPLETE   0x1
#define EPINT_FIFO_ERROR        0x2
#define EPINT_DMA_COMPLETE      0x4


#define USB20FUNCTION_DEFAULT_PRIORITY    100

#define USB20FUNCTION_PRIORITY_VALNAME    TEXT("Priority256")
#define USB20FUNCTION_PRIORITY_VALTYPE    REG_DWORD
// Debugging only registry.
#define USB20FUNCTION_EP0_STALL_COUNTER_VALNAME TEXT("EP0StallCounter")
#define USB20USBFUNCTION_EP0_STALL_COUNTER_VALTYPE REG_DWORD
#define USB20USBFUNCTION_BAD_SETUP_COUNTER_VALNAME TEXT("BadSetupCounter")
#define USB20USBFUNCTION_BAD_SETUP_COUNTER_VALTYPE REG_DWORD

#define USB20USBFUNCTION_DEFAULT_PRIORITY    100

#ifdef DEBUG 
#define ZONE_DATA DEBUGZONE(11)
#define ZONE_DMAOUT  DEBUGZONE(10)
#define ZONE_DMAIN  DEBUGZONE(9)
#endif

#define U2D_EP0_MAX_PACKET_SIZE 64

/// Endpoint Container 
/// Empty Class, just provide class type
class CEndpointContainer : public CStaticContainer <USB20Endpoint, XLLP_U2D_USB_MAX_EP_NUM>
{
};

/// USB Device class
/// This is the main class of UDC driver
class USB20Device :public CEndpointContainer, public CRegistryEdit, public CMiniThread 
{
public:
   	/// Contruct function
	/// @param 	lpActivePath	[IN] Active Key for the interface driver
    USB20Device(LPCTSTR lpActivePath);


	/// Deconstruction Function
	/// Unmap address, close handle
    virtual ~USB20Device();

	VOID WriteULPIReg(BYTE reg, BYTE value);

	/// PDD Initialized
	/// Map IO Space, init hardware
	/// @param 	pvMddContext		[IN]Mdd Context
	/// @param 	pMddInterfaceInfo		[IN]MDD interface function infomation
	/// @param 	pPddInterfaceInfo		[OUT] Pdd Interface info, set this point
	/// @return  ERROR_SUCCESS 		Success, 	
	///			 other value 	failed
    virtual DWORD Init(PVOID pvMddContext,
        PUFN_MDD_INTERFACE_INFO pMddInterfaceInfo, PUFN_PDD_INTERFACE_INFO pPddInterfaceInfo);
//  PDD interface.
	/// Remove all endpoint
	/// @return 	TRUE	Success
	///				FALSE	Fail
    virtual BOOL DeleteAllEndpoint();
// Endpoint Function.
	/// Check Endpoint if support 
	/// Endpoint will be initialized 
	///
	/// @param 	dwEndpoint			[IN] Endpoint Number
	/// @param  Speed				[IN] Bus speed, high or Full
	/// @param  pEndpointDesc		[IN] Endpoint descriptor
	/// @param  bConfigurationValue  [IN] Configuration number
	/// @param  bInterfaceNumber		[IN] Interface Number
	/// @param  bAlternateSetting		[IN] Alternate setting number
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD IsEndpointSupportable (DWORD dwEndpoint,UFN_BUS_SPEED Speed,PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc,
            BYTE bConfigurationValue=1, BYTE bInterfaceNumber=0, BYTE bAlternateSetting=0 );
	/// Initialze endpoint
	///
	/// @param 	dwEndpoint			[IN] Endpoint Number
	/// @param  Speed				[IN] Bus speed, high or Full
	/// @param  pEndpointDesc		[IN] Endpoint descriptor
	/// @param  bConfigurationValue  [IN] Configuration number
	/// @param  bInterfaceNumber		[IN] Interface Number
	/// @param  bAlternateSetting		[IN] Alternate setting number
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD InitEndpoint(DWORD dwEndpoint,UFN_BUS_SPEED Speed,PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc,
            BYTE bConfigurationValue=1, BYTE bInterfaceNumber=0, BYTE bAlternateSetting=0 );


	/// Deinit Endpoint 
	/// @param 	dwEndpoint 		[IN] Endpoint Number
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD DeinitEndpoint(DWORD dwEndpoint );

	/// Send Stall at Endpoint
	/// @param 	dwEndpoint 		[IN] Endpoint Number
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD StallEndpoint(DWORD dwEndpoint );

	/// Clear Stall at Endpoint
	/// @param 	dwEndpoint 		[IN] Endpoint Number
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD ClearEndpointStall( DWORD dwEndpoint );


	/// Reset Endpoint
	/// @param 	dwEndpoint 		[IN] Endpoint Number
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD ResetEndpoint(DWORD dwEndpoint );

	/// Check Endpoint status
	/// @param 	dwEndpoint 		[IN] Endpoint Number
	/// @param  pfHalted			[OUT] return if endpoint halt
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD IsEndpointHalted( DWORD dwEndpoint, PBOOL pfHalted );

	/// Start a transfer at the special Endpoint
	/// @param 	dwEndpoint 		[IN] Endpoint Number
	/// @param  pTransfer			[IN] Data structure will be transfered
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD IssueTransfer(DWORD  dwEndpoint,PSTransfer pTransfer );


	/// Give up a transfer at the special Endpoint
	/// @param 	dwEndpoint 		[IN] Endpoint Number
	/// @param  pTransfer			[IN] Data structure will be transfered
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD AbortTransfer(DWORD dwEndpoint, PSTransfer pTransfer);

	/// Send Zero handshake package at endpoint 0
	/// @param 	dwEndpoint 		[IN] Endpoint Number
	/// @param  pTransfer			[IN] Data structure will be transfered
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
	/// @remarks  Endpoint Zero Special
    virtual DWORD SendControlStatusHandshake(DWORD dwEndpoint);
//  Device Function.
	/// Start Device
	/// Initialize all opened endpoint
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD Start();

	/// Stop Device
	/// DeInitialize all opened endpoint
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
    virtual DWORD Stop();

	/// Check if usb Cable attached
	/// @return 	TRUE		Attached
	///				FALSE		Detached
    virtual BOOL IsCableAttached() { return TRUE; };
	/// Set Address
	/// UDC handle it automatically. Software do nothing
	/// @return 	ERROR_SUCCESS			Success
    virtual DWORD  SetAddress( BYTE  bAddress );
	
    /// Initiate RemoteWakeup
    /// force the UDC out of suspend
    /// @return     ERROR_SUCCESS           Success
    virtual void  Initiate_RemoteWakeup();

	///Power Down which called when system suspend. 
    virtual void PowerDown();

	///Power Up which called when system resume. 
    virtual void PowerUp() ;

	///Set Power State
	/// @param cpsNew 	[IN] new power state
    virtual void  SetPowerState( CEDEVICE_POWER_STATE cpsNew ) ;

	/// IO Control
	/// @return 	ERROR_SUCCESS			Success
	///				Other Value				Fail
	/// @remarks IOCTL_UFN_GET_PDD_INFO tell MDD, PDD is able to support DMA. 
    virtual DWORD IOControl( IOCTL_SOURCE source, DWORD dwCode, PBYTE  pbInBuf, DWORD cbInBuf, PBYTE pbOutBuf, DWORD cbOutBuf,PDWORD  pcbActualOutBuf );

//  Register Access.
    
// Device Register Access.
        
    // Interrupt
   /// Interrupt
    /// Enable/Disable Endpoint Interrupt
    /// @param dwEndpointIndex		[IN] Endpoint Number
    /// @param bEnable				[IN] TRUE enable, FALSE disable
    /// @return  	TRUE	Sucess
    ///				FALSE	Fail
    BOOL    EnableEndpointInterrupt(DWORD dwEndpointIndex,BOOL bEnable);
    DWORD   GetEndpointIntrStatus(DWORD dwEndpointIndex);


    /// Call MDD notify function to tell MDD transfer complete
    /// @param 	pTransfer  [IN] Data transfer structure
    void MddTransferComplete(PSTransfer pTransfer) {
        SETFNAME();
        if (m_pvMddContext && pTransfer) {
            DEBUGMSG(ZONE_FUNCTION, (_T("%s MddTransferComplete pTransfer:0x%x"),pszFname,pTransfer));
            m_pfnNotify(m_pvMddContext, UFN_MSG_TRANSFER_COMPLETE, (DWORD) pTransfer);
        }
    }

	/// Send Device Nofity message to MDD
	/// @param 		dwMsg		[IN] Message type
	/// @param		dwParam		[IN] Message param
	/// @return     TRUE	Success
	///				FALSE	Fail
    BOOL DeviceNotification( DWORD dwMsg, DWORD dwParam ) {
        SETFNAME();
        if (m_pvMddContext) {
            DEBUGMSG(ZONE_FUNCTION, (_T("%s DeviceNotification dwMsg:0x%x,dwParam:0x%x"),pszFname,dwMsg,dwParam));
            return m_pfnNotify(m_pvMddContext, dwMsg, dwParam);
        }
        else {
            DebugBreak();
            return FALSE;
        }
    }

public:
    /// Inc Ep0 Stall coundter
    /// @remarks Debugging function.
    void IncEp0StallCounter() {
#ifdef ERRORCOUNTERINREGISTRY
        DWORD dwEp0StallCounter = 0;
        if (!GetRegValue(USB20FUNCTION_EP0_STALL_COUNTER_VALNAME,(LPBYTE) &dwEp0StallCounter,sizeof(dwEp0StallCounter))) {
            dwEp0StallCounter = 0;
        }
        dwEp0StallCounter++;
        RegSetValueEx( USB20FUNCTION_EP0_STALL_COUNTER_VALNAME,USB20USBFUNCTION_EP0_STALL_COUNTER_VALTYPE,
            (PBYTE)&dwEp0StallCounter,sizeof(dwEp0StallCounter));
#endif
    }

    /// Inc Ep0 Bad Setup coundter
    /// @remarks Debugging function.
    void IncBadSetupCounter() {
#ifdef ERRORCOUNTERINREGISTRY
        DWORD dwBadSetupCounter = 0;
        if (!GetRegValue(USB20USBFUNCTION_BAD_SETUP_COUNTER_VALNAME,(LPBYTE) &dwBadSetupCounter,sizeof(dwBadSetupCounter))) {
            dwBadSetupCounter = 0;
        }
        dwBadSetupCounter++;
        RegSetValueEx( USB20USBFUNCTION_BAD_SETUP_COUNTER_VALNAME, USB20USBFUNCTION_BAD_SETUP_COUNTER_VALTYPE,
            (PBYTE)&dwBadSetupCounter,sizeof(dwBadSetupCounter));
#endif
    }

public:

	/// Get Xllp Handle for U2D
	/// @return handle of XLLP
	inline P_XLLP_U2D_T GetXllpHandle(){return &m_XllpU2DHandle;}
	
	P_XLLP_U2D_REGISTERS_T  m_pRegsBase;          ///< Pointer to U2D.0's registers
 	P_XLLP_VUINT32_T	 	m_pMfpRegBase; 				///< Pointer to the MFP base registers
	P_XLLP_GPIO_T 			m_pGPIORegs;					///< Pointer to the GPIO base registers
protected: 
	

	/// Power Manage Function
	/// @param boff 	TRUE: suspend  FALSE: resume
    virtual void PowerMgr(BOOL bOff);

	
    
    UFN_PDD_INFO m_PDDInfo; ///< PDD Info, tell MDD support DMA
        
	// IST
    DWORD       m_dwSysIntr;  ///< System Interrupt Number
    HANDLE      m_hISTEvent;  ///< IST event
    DWORD       m_dwPriority; ///< IST thread priority

	BOOL            m_fDoubleBuffer; ///< Does support double buffer

	BOOL    m_fIsCableAttached;    ///< Is Cable Attached
	BOOL 	m_fResumeOccurred;     ///< If Resume happen
	BOOL 	m_fForceResume;        ///< force enumeration when resume
	
	PVOID       m_pvMddContext; 	///< MDD Context
	P_XLLP_CLKMGR_T m_pDCCLKReg;	///< Clock manage base virtual address
	
    // Protected Fucntion
// Protected Fucntion
    /// Hardware Init
    /// Clear all interrupt status. enable UDE
    /// @return 	TRUE	Success
    ///				FALSE	Fail
    BOOL        HardwareInit();
    BOOL        ReInit(); // For Cable Detach & Attach , We have to re-init the Device Controller.
    // Device Info.

	DWORD       m_dwCurConfigure;	///< Current Configure
    DWORD       m_dwCurInterface;	///< Current Interface number
    
    PFN_UFN_MDD_NOTIFY      m_pfnNotify;		///<MDD event nofity call back function
    CEDEVICE_POWER_STATE    m_CurPowerState;		///< Current Power State
    HANDLE                  m_hParent;			///< Parant bus handle

	DWORD		m_busSpeed;				///< Bus Speed High or Full
	
private:
	XLLP_U2D_T m_XllpU2DHandle;			///< Xllp U2D handle

	/// Init MFP Resource manage
	/// @return 	TRUE		Success
	///				FALSE		Fail
	BOOL InitMFPRM();

	/// IST Thread 
	DWORD ThreadRun();

	HANDLE m_MfpRMDHandle;					///< MFP Resource manage handle
	P_XLLP_MFP_RM_DB_ID_T m_pMfpRMDb;		///< U2D Resouce ID
	
};

/// Endpoint base Class
/// Handle All endpoint related operation
class USB20Endpoint: public CRefObject,public CLockObject 
{
public :
	/// Contruct function
	/// Init member varible, allocate DMA buffer if DMA enable
	/// @param pUsbDevice 		[IN]	UDC Devive object
	/// @param dwPipeIndex		[IN] Pipe Number, equal with Endpoint number
	/// @param bDoubleBuffer		[IN] Enable/Disable Double buffer
	/// @param bDMAEnable		[IN] Enable/Disable DMA support
    USB20Endpoint(USB20Device * const pUsbDevice, const DWORD dwPipeIndex,BOOL bDoubleBuffer = TRUE);

	///	Deconstruction Function
	///	upmap address, close handle, free DMA memory    
    virtual ~USB20Endpoint();

	/// Init Endpoint
	/// @param  pEndpointDesc		[IN] Endpoint descriptor
	/// @param  bConfigurationValue  [IN] Configuration number
	/// @param  bInterfaceNumber		[IN] Interface Number
	/// @param  bAlternateSetting		[IN] Alternate setting number
	/// @return  	 TRUE			Success
	/// 			 FALSE  		Fail
    virtual BOOL Init(PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc,
            BYTE bConfigurationValue, BYTE bInterfaceNumber, BYTE bAlternateSetting);
	/// Reinit Endpoint 
    virtual BOOL ReInit();

	/// Clear DMA Status
	void ClearDMAStatus()
    {
	    XLLP_UINT32_T tmpDcsrClear = m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex] & XLLP_DCSR_WRITABLES_MSK;
	    // Stop intr is not cleared by a simple write-back.  Must also
        //  restart the DMA (not done in ISR)
       	if (m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex] & XLLP_DMAC_DCSR_STOP_INTR)
              tmpDcsrClear &= ~(XLLP_DMAC_DCSR_STOP_IRQ_EN);
                // Clear the status
      	m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex]  = tmpDcsrClear;
		    	
    }

	/// Stop DMA Transfer
	void StopDMATransfer()
	{

		XLLP_UINT32_T temp=m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex] ;
		temp &= XLLP_DCSR_WRITABLES_MSK; 
		temp &=~ XLLP_DMAC_DCSR_RUN;
		m_pU2DRegsBase->u2ddmacsr[m_dwEndpointIndex] = temp;
	}

		
    /// Init Endpoint 
    /// @param Speed		  [IN]Bus Speed (High or Full)
    /// @param pEndpointDesc  [IN]Endpoint Descriptor
    /// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail
    virtual DWORD InitEndpoint(UFN_BUS_SPEED Speed,PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc) 
    {
        // We should Reset Data Toggle Bit to DATA0. But we do know how.
        if( Init(pEndpointDesc,m_bConfigurationValue,m_bInterfaceNumber,m_bAlternateSetting) )
		 	return ERROR_SUCCESS;

		return ERROR_INVALID_DATA;
        
    }

	/// Deinit endpoint
	/// Disable alll Endpoint interrupt
	/// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail
    virtual DWORD DeinitEndpoint() 
	{
        return XllpU2DDisableInterrupt(	m_pUsbDevice->GetXllpHandle(), 
        								(XLLP_U2D_INTERRUPTS_T)m_dwEndpointIndex,
        								(XLLP_U2D_EP_INTERRUPT_TYPE_T)(U2D_SHORT_PACKET_COMPL_INT|U2D_PACKET_COMPL_INT)
        								);
    }
	
	/// Send Stall at this endpoint
	/// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail
    virtual DWORD StallEndpoint();

	/// Clear stall status
	/// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail
    virtual DWORD ClearEndpointStall();

	/// Reset this endpoint
	/// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail
    virtual DWORD ResetEndpoint();

	/// Is This Endpoint hanlted
	/// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail
    virtual DWORD IsEndpointHalted(PBOOL pfHalted );


	/// Start new transfer
	/// @param 	pTransfer		[IN] Data structure will be transfered
	/// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail	
    virtual DWORD IssueTransfer(PSTransfer pTransfer ) ;

	/// Abort current transfer
	/// @param 	pTransfer		[IN] Data structure will be transfered	
	/// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail
    virtual DWORD AbortTransfer(PSTransfer pTransfer );

	/// Is Control status hand shake
	/// @remarks 	Only EP0 use it
	/// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail
    virtual DWORD SendControlStatusHandshake() { return ERROR_INVALID_PARAMETER; };

   	/// Get This endpoint descriptor
	/// @return 	This endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR GetEndpointDescriptor() { return m_epDesc; };

   	/// IST
	/// @return 	ERROR_SUCCESS		Success
    ///				Other				Fail
    virtual DWORD   IST(DWORD dwIRBit, DWORD DMA=0) = 0 ;

	/// Start DMA transfer
    virtual void StartDMA(){};

#ifdef DEBUG
	/// Dump descriptor
	/// @remarks 	Debug purpose
	void DumpDescript();
#endif

protected:

    USB20Device * const    m_pUsbDevice;						///<!USB Device object
	volatile P_XLLP_U2D_REGISTERS_T  m_pU2DRegsBase;			///< U2D register virtual address
	
    const XLLP_U2D_EP_T             m_dwEndpointIndex;			///< endpoint Index
    USB_ENDPOINT_DESCRIPTOR m_epDesc;							///< endpoint descriptor
    BYTE            m_bConfigurationValue,m_bInterfaceNumber,m_bAlternateSetting;
    volatile ULONG *        m_dataport;							///< FIFO Physical address
    
    BOOL            m_fDoubleBuffer;							///< is double buffer enabled
    PSTransfer      m_pCurTransfer;								///< current transfer data structure
    BOOL            m_fZeroPacket;								///< is send zero package
    BOOL            m_fStalled;									///< is send stall
    
    // DMA support	
    volatile XLLP_UINT8_T *     m_vDMAData;				///< DMA data buffer virtual pointer
	XLLP_UINT32_T		m_phyDMAData;					///< DMA data buffer physical pointer

	DMA_ADAPTER_OBJECT m_DmaAdapter;					///< DMA adaptor object, required by XLLP_DMAC module

    
    XLLP_DMAC_DESCRIPTOR_T * m_vDesc;					///< DMA descriptor array, virtual address
    XLLP_UINT32_T		m_phyDesc;						///< DMA descriptor array, physical address
    	
    PHYSICAL_ADDRESS		m_PA;						///< Physicall address
    
    BOOL                m_bTerminated;     				///< is IST terminated

    
    int         m_Counter;								///< Transfer Counter Debug purpose
    int         m_LastTransfer;							///< last Transfer


//  Help Function.
    /// Complete Transfer.
    /// @param dwError      [IN] Error Code
    /// @return  Have transferred data structure
    PSTransfer CompleteTransfer(DWORD dwError);

    /// Send Fake Feature to MDD
    /// @param  bRequest        [IN] Request number
    /// @param  wFeatureSelector    [IN] Feature Selector
    /// @remarks UDC hardware can handle some request automatically. I need Fake request to send to MDD. 
    void SendFakeFeature(BYTE bReuqest,WORD wFeatureSelector);

    /// Send Data to FIFO
    /// @param  pBuffer         [IN] Data buffer
    /// @param  dwLength        [IN] Data lenght
    /// @return  length have transferred actually
    DWORD XmitData(PBYTE pBuffer, DWORD dwLength);

    /// Get Data From  FIFO
    /// @param  pBuffer         [IN] Data buffer
    /// @param  dwLength        [IN] Data lenght
    /// @return  length have transferred actually
    DWORD ReceiveData(PBYTE pBuffer, DWORD dwLength);    
};

#define EP0_MAX_PACKET_SIZE 0x10 

/// Endpoint Zero class
class USB20EndpointZero : public USB20Endpoint {
public:
    USB20EndpointZero(USB20Device * const pUsbDevice, BOOL bDoubleBuffer = TRUE ) 
        : USB20Endpoint(pUsbDevice, 0 ,bDoubleBuffer) 
    {
        m_bNeedAck = FALSE;
        m_bSetupDirIn = FALSE;
        m_fInIST = FALSE;
    }
    BOOL Init(PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc,
            BYTE bConfigurationValue, BYTE bInterfaceNumber, BYTE bAlternateSetting);   
    virtual BOOL ReInit();
    DWORD ResetEndpoint();
    DWORD IssueTransfer(PSTransfer pTransfer );
    DWORD SendControlStatusHandshake() ;
    DWORD   IST(DWORD dwIRBit,DWORD DMA=0);
protected:
    
    /// Need send ACK (zero package ) to host
    BOOL  m_bNeedAck;       
    BOOL  m_bSetupDirIn;        ///< Transfer Dir (IN or OUT)
    BOOL  m_fInIST ;            ///<    Is In IST
    
private:
    USB_DEVICE_REQUEST m_backup_udr;    ///< Backup UDR
    USB_DEVICE_REQUEST m_cur_udr;       ///< Current UDR
    BOOL               m_fBackedudr;        ///< is force backeupdr
};
///IN Endpoint Class
class USB20EndpointIn : public USB20Endpoint  
{
public:
    USB20EndpointIn(USB20Device * const pUsbDevice,DWORD dwEndpointIndex, BOOL bDoubleBuffer = TRUE);
		
	DWORD   IST(DWORD dwIRBit,DWORD) ;
private:
    void StartDMA();	
	
};

///Out Endpoint Class
class USB20EndpointOut : public USB20Endpoint  
{

public:
    USB20EndpointOut(USB20Device * const pUsbDevice,DWORD dwEndpointIndex, BOOL bDoubleBuffer = TRUE );
	DWORD   IST(DWORD dwIRBit,DWORD DMA=0) ;

private:

    
    void StartDMA();	
    /// Copy data from DMA buffer to user buffer
    /// @returns  Data size have been copyed.    
	DWORD UpdateFromDMABuffer();
};

/// Create USB Function driver object.  Platform related code create finial object
/// @param  lpActivePath        [IN] Active Key for the interface driver
/// @return     USB Function PDD Driver object
USB20Device * CreateUSB20Device(LPCTSTR lpActivePath);

#endif




